#include "ulib.h"
#include "sysenv.h"
#include "syscall.h"
#include "mod_sym.h"

extern char spin[];

#define BASE_TESTBENCH 0
#define BT_PPAGE_AF 1
#define BT_PROC_ENV 1
#define BT_MALLOC   1

#define NORMAL      1

void
print_backtrace(void)
{
	 uint32_t eip;
	 uint32_t ebp, nebp;
	 asm volatile("movl %%ebp, %0" : "=r" (ebp));

     sc_kprintf("Stack backtrace:\n");
     while (1)
     {
		  asm volatile("movl 4(%0), %1" : "=r" (eip) : "r"(ebp));
		  asm volatile("movl (%0), %1"
					   : "=r" (nebp)
					   : "q" (ebp)
			   );
		  sc_kprintf("  ebp: %08x  eip: %08x\n", ebp, eip);
		  if ((ebp = nebp) == 0) break;
	 }
}

void
user_entry(void)
{
	 if (cur_pid() == 0)
	 {
		  sc_kprintf("Welcome to the EKOS user land.\n");
		  
#if BASE_TESTBENCH
		  sc_kprintf("Executing base testbench.\n");

#if BT_PPAGE_AF
		  sc_kprintf("ppage alloc/free:\n");

		  physaddr_t p1, p2, p3;
		  sc_ppage_alloc(1, &p1);
		  sc_ppage_alloc(2, &p2);
		  sc_ppage_alloc(3, &p3);

		  sc_kprintf("\talloc1 %08x %08x %08x\n", p1, p2, p3);

		  sc_ppage_free(p1);
		  sc_ppage_free(p2);
		  sc_ppage_free(p3);

		  sc_ppage_alloc(4, &p1);
		  sc_ppage_alloc(5, &p2);
		  sc_ppage_alloc(6, &p3);

		  sc_kprintf("\talloc2 %08x %08x %08x\n", p1, p2, p3);

		  sc_ppage_free(p1);
		  sc_ppage_free(p2);
		  sc_ppage_free(p3);

		  sc_ppage_alloc(7, &p1);
		  sc_ppage_alloc(8, &p2);
		  sc_ppage_alloc(9, &p3);

		  sc_kprintf("\talloc3 %08x %08x %08x\n", p1, p2, p3);

		  sc_ppage_free(p1);
		  sc_ppage_free(p2);
		  sc_ppage_free(p3);

#endif

#if BT_PROC_ENV
		  sc_kprintf("proc/env create/attach/detach/destroy:\n");
		  int pid = sc_proc_fork(cur_pid(), spin, NULL);
		  sc_kprintf("forked remote pid: %d\n", pid);

		  int tmp;
		  volatile int delay;
	 	 
		  tmp = sc_proc_attach(pid);
		  sc_kprintf("proc attach, result = %e\n", tmp);

		  for (delay = 0; delay != 100000000; ++ delay) ;

		  tmp = sc_proc_detach(pid);
		  sc_kprintf("proc detach, result = %e\n", tmp);

		  for (delay = 0; delay != 100000000; ++ delay) ;

		  tmp = sc_proc_kill(pid);
		  sc_kprintf("proc kill, result = %e\n", tmp);

		  sc_kprintf("env test missing\n");
#endif


#if BT_MALLOC
		  sc_kprintf("malloc test\n");
		  
		  mm_init();

		  void *a1, *a2, *a3, *a4;
		  a1 = malloc(8);
		  a2 = malloc(10);
		  a3 = malloc(13);
		  a4 = malloc(1 << 20);

		  sc_kprintf("\tmalloc1 %08x %08x %08x %08x\n", a1, a2, a3, a4);

		  free(a1); free(a2); free(a3); free(a4);

		  a1 = malloc(8);
		  a2 = malloc(10);
		  a3 = malloc(13);
		  a4 = malloc(1 << 20);

		  sc_kprintf("\tmalloc2 %08x %08x %08x %08x\n", a1, a2, a3, a4);

		  free(a1); free(a2); free(a3); free(a4);

		  a1 = malloc(8);
		  a2 = malloc(10);
		  a3 = malloc(13);
		  a4 = malloc(1 << 20);

		  sc_kprintf("\tmalloc3 %08x %08x %08x %08x\n", a1, a2, a3, a4);

		  free(a1); free(a2); free(a3); free(a4);
#endif
		  
		  sc_kprintf("testbench end, now loop.\n");

#endif

#if NORMAL
		  /* Here starts to initialize base lib */
		  mm_init();
		  // kv_init();
		  rkv_init();
		  elf_mod_init();

		  /* register mods */
		  char *cur, *end, *last;
		  uint32_t size;
		  int id = 0;
		  
		  rkv_get(0, (const char **)&cur, &size);

		  end = cur + size;
		  last = cur;
		  
		  for (; cur < end; ++ cur)
		  {
			   if (*cur == ' ' || *cur == '\r' || *cur == '\n')
			   {
					if (last != cur)
					{
						 *cur = 0;
						 if (*last != '-')
						 {
							  elf_mod_register(last, id);
						 }

						 ++ id;
					}
					last = cur + 1;
			   }
		  }

		  /* testing symbol */
		  elf_mod_touch_symbol("printf",  &sc_kprintf, 0);
		  elf_mod_touch_symbol("vprintf", &sc_kvprintf, 0);
		  elf_mod_touch_symbol("vsnprintf", &vsnprintf, 0);
		  elf_mod_touch_symbol("snprintf", &snprintf, 0);
		  elf_mod_touch_symbol("sysconf", &sysconf, 0);
		  elf_mod_touch_symbol("export_symbol", &export_symbol, 0);
		  elf_mod_touch_symbol("vpt", vpt, 0);
		  elf_mod_touch_symbol("vpd", vpd, 0);
		  elf_mod_touch_symbol("print_backtrace", &print_backtrace, 0);
		  
		  elf_mod_touch_symbol("mmap_set", &self_mmap_set, 0);
		  elf_mod_touch_symbol("mmap_get", &self_mmap_get, 0);

		  elf_mod_touch_symbol("malloc", &malloc, 0);
		  elf_mod_touch_symbol("free", &free, 0);
		  elf_mod_touch_symbol("bmalloc", &bmalloc, 0);
		  elf_mod_touch_symbol("bfree", &bfree, 0);
		  elf_mod_touch_symbol("pmalloc", &pmalloc, 0);
		  elf_mod_touch_symbol("pfree", &pfree, 0);
		  elf_mod_touch_symbol("vmalloc", &vmalloc, 0);
		  elf_mod_touch_symbol("vfree", &vfree, 0);

		  elf_mod_touch_symbol("strlen",  &strlen, 0);
		  elf_mod_touch_symbol("strnlen", &strnlen, 0);
		  elf_mod_touch_symbol("strcat",  &strcat, 0);
		  elf_mod_touch_symbol("strcpy",  &strcpy, 0);
		  elf_mod_touch_symbol("strncpy", &strncpy, 0);
		  elf_mod_touch_symbol("strlcpy", &strlcpy, 0);
		  elf_mod_touch_symbol("strcmp",  &strcmp, 0);
		  elf_mod_touch_symbol("strncmp", &strncmp, 0);
		  elf_mod_touch_symbol("strchr",  &strchr, 0);
		  elf_mod_touch_symbol("strfind", &strfind, 0);

		  elf_mod_touch_symbol("memmove", &memmove, 0);
		  elf_mod_touch_symbol("memcpy",  &memmove, 0);
		  elf_mod_touch_symbol("memcmp",  &memcmp, 0);
		  elf_mod_touch_symbol("memset",  &memset, 0);
		  elf_mod_touch_symbol("memfind", &memfind, 0);

		  elf_mod_touch_symbol("process_create", &process_create, 0);
		  elf_mod_touch_symbol("process_create_wait", &process_create_wait, 0);
		  elf_mod_touch_symbol("schedule", &sc_yield, 0);
		  elf_mod_touch_symbol("cur_pid", &cur_pid, 0);
		  elf_mod_touch_symbol("process_set_data", &proc_set_data, 0);
		  elf_mod_touch_symbol("process_get_data", &proc_get_data, 0);
		  elf_mod_touch_symbol("exit", &sc_exit, 0);
		  
		  elf_mod_touch_symbol("wait_pretend", &sc_wait_pretend, 0);
		  elf_mod_touch_symbol("wait_try", &sc_wait_try, 0);
		  elf_mod_touch_symbol("wait", &sc_wait, 0);
		  elf_mod_touch_symbol("notify", &sc_notify, 0);
		  elf_mod_touch_symbol("notify_ex", &sc_notify_ex, 0);
		  elf_mod_touch_symbol("set_soft_timer", &sc_set_soft_timer, 0);

		  elf_mod_touch_symbol("uips_is_finish", &uips_is_finish, 0);
		  elf_mod_touch_symbol("uips_wait", &uips_wait, 0);
		  elf_mod_touch_symbol("uips_wait_try", &uips_wait, 0);

		  elf_mod_touch_symbol("semaphore_init", &semaphore_init, 0);
		  elf_mod_touch_symbol("semaphore_try_acquire", &semaphore_try_acquire, 0);
		  elf_mod_touch_symbol("semaphore_acquire", &semaphore_acquire, 0);
		  elf_mod_touch_symbol("semaphore_ac_break", &semaphore_ac_break, 0);
		  elf_mod_touch_symbol("semaphore_release", &semaphore_release, 0);

		  elf_mod_touch_symbol("mutex_init", &mutex_init, 0);
		  elf_mod_touch_symbol("mutex_try_acquire", &mutex_try_acquire, 0);
		  elf_mod_touch_symbol("mutex_acquire", &mutex_acquire, 0);
		  elf_mod_touch_symbol("mutex_ac_break", &mutex_ac_break, 0);
		  elf_mod_touch_symbol("mutex_release", &mutex_release, 0);
		  
		  elf_mod_touch_symbol("ips_recv", &sc_recv, 0);
		  elf_mod_touch_symbol("ips_recv_try", &sc_recv_try, 0);
		  elf_mod_touch_symbol("ips_recv_break", &sc_recv_break, 0);

		  /* load mods */
		  rkv_get(1, (const char **)&cur, &size);

		  end = cur + size;
		  last = cur;
		  
		  for (; cur < end; ++ cur)
		  {
			   if (*cur == ' ' || *cur == '\r' || *cur == '\n')
			   {
					if (last != cur)
					{
						 *cur = 0;
						 if (*last != '-')
						 {
							  elf_mod_load(last);
						 }
					}
					last = cur + 1;
			   }
		  }
#endif
	 }

	 sc_kprintf("Now become idle!\n");
	 if (cur_pid() == 0)
	 {
		  uint64_t info;
		  while (1)
		  {
			   sc_recv(procs[0].ex_ap, 0);
			   while (sc_recv_try(0, IPS_WAIT, &info) != 0) ;
			   if ((info & 0xffff) == EX_SYS_KILL)
			   {
					int pid = (info >> 16) & 0xffff;
					sc_proc_detach(pid);
					sc_proc_kill(pid);
			   }
		  }
	 }
	 else
	 {
		  while (1) sc_wait();
	 }
}
